﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Newtonsoft.Json;
using MessageQuque.Common;
using RabbitMQ.Client;
using MessageQuque.Common.Base.Business;
using MessageQuque.Server.Enums;

namespace MessageQuque
{
    public abstract class ReceiverBase
    {
        // 使用ConnectionFactory创建连接
        private static ConnectionFactory cf = new ConnectionFactory();

        static ReceiverBase()
        {
            // 使用前文的配置环境信息
            cf.UserName = Config.UserName;
            cf.Password = Config.Password;
            cf.VirtualHost = Config.VirtualHost;
            cf.RequestedHeartbeat = 0;
            cf.uri = new Uri(Config.UriAddress);
        }

        /// <summary>
        /// 出队
        /// </summary>
        /// <param name="queueName">队列名称</param>
        protected IDictionary<Status, int> Dequeue<T>(string queueName)
        {
            IDictionary<Status, int> list = new Dictionary<Status, int>();
            int successCount = 0, failCount = 0;
            using (IConnection conn = cf.CreateConnection())
            {
                using (IModel ch = conn.CreateModel())
                {
                    //普通使用方式BasicGet
                    //noAck = true，不需要回复，接收到消息后，queue上的消息就会清除
                    //noAck = false，需要回复，接收到消息后，queue上的消息不会被清除
                    //直到调用channel.basicAck(deliveryTag, false); queue上的消息才会被清除
                    //而且，在当前连接断开以前，其它客户端将不能收到此queue上的消息
                    while (true)
                    {
                        try
                        {
                            ch.QueueDeclare(queueName, true, false, false, null);//队列定义
                            BasicGetResult result = ch.BasicGet(queueName, false);
                            var acceptOn = DateTime.Now;
                            if (result == null) break;

                            var header = UTF8Encoding.UTF8.GetString((byte[])result.BasicProperties.Headers["header"]);
                            var body = UTF8Encoding.UTF8.GetString(result.Body).Replace("\0\0\0body\0\n", "");//去掉头部信息;

                            if (typeof(T).Equals(typeof(string)))
                            {
                                //处理相应的业务逻辑
                                Business.Process(queueName, body);
                                //发送应答包
                                ch.BasicAck(result.DeliveryTag, false);
                                successCount++;
                                Logger.Info(string.Format("处理成功：queueName={0},{1}", queueName, body));
                                continue;
                            }

                            T message = body.DeserializeFromJson<T>();

                            var queueId = message.GetValue("QueueId");

                            try
                            {
                                //处理相应的业务逻辑
                                Business.Process(queueName, message);
                                //发送应答包
                                ch.BasicAck(result.DeliveryTag, false);
                                successCount++;
                                Logger.Info(string.Format("处理成功：queueName={0}\r\nMessage：{1}", queueName, body));
                            }
                            catch (Exception ex)
                            {
                                failCount++;
                                Logger.Error(string.Format("处理失败：queueName={0},{1}。\r\nError:{2}", queueName, body, ex.Message), ex);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Error(string.Format("处理失败：queueName={0}", queueName));
                            Logger.Error(ex.Message, ex);
                        }
                    }
                }
            }

            list.Add(Status.Success, successCount);
            list.Add(Status.Failure, failCount);
            list.Add(Status.All, successCount + failCount);
            return list;
        }

        public IBusiness Business { get; set; }
    }
}
